﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Lab3.Entities
{
    class Reflectionsphere : Entity
    {
        private EnvironmentMapEffect _environmentMapEffect;
        private RenderTargetCube _renderTargetCube;
        private GraphicsDevice _device;
        private Effect _bumpEffect;
        private Texture2D _bumpTexture;

        public Matrix View { get; set; }
        public Matrix Projection { get; set; }

        public Reflectionsphere(Camera camera, GraphicsDevice device, Effect effect, Texture2D texture) : base(camera)
        {
            _device = device;
            _bumpEffect = effect;
            _bumpTexture = texture;
            _environmentMapEffect = new EnvironmentMapEffect(_device);
            _renderTargetCube = new RenderTargetCube(_device, 512, false, SurfaceFormat.Color, DepthFormat.Depth16);

            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, 1, 0.1f, 600f);
        }

        public void CreateCubeMap(CubeMapFace cubeMapFace)
        {
            _environmentMapEffect.GraphicsDevice.SetRenderTarget(_renderTargetCube, cubeMapFace);

            switch (cubeMapFace)
            {
                case CubeMapFace.NegativeX:
                    Camera.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Left, Vector3.Up);
                    Camera.Projection = Projection;
                    break;
                case CubeMapFace.PositiveX:
                    Camera.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Right, Vector3.Up);
                    Camera.Projection = Projection;
                    break;
                case CubeMapFace.NegativeY:
                    Camera.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Down, Vector3.Forward);
                    Camera.Projection = Projection;
                    break;
                case CubeMapFace.PositiveY:
                    Camera.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Up, Vector3.Forward);
                    Camera.Projection = Projection;
                    break;
                case CubeMapFace.NegativeZ:
                    Camera.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Forward, Vector3.Up);
                    Camera.Projection = Projection;
                    break;
                case CubeMapFace.PositiveZ:
                    Camera.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Backward, Vector3.Up);
                    Camera.Projection = Projection;
                    break;
            }
        }

        public void EndCubeMap()
        {
            _environmentMapEffect.GraphicsDevice.SetRenderTarget(null);
        }

        public override void Draw(int type)
        {
            foreach (ModelMesh mesh in Model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    // General
                    _bumpEffect.Parameters["World"].SetValue(ObjectWorld);
                    _bumpEffect.Parameters["View"].SetValue(Camera.View);
                    _bumpEffect.Parameters["Projection"].SetValue(Camera.Projection);
                    _bumpEffect.Parameters["ViewVector"].SetValue(Camera.Position);
                    _bumpEffect.Parameters["CameraPos"].SetValue(Camera.Position);

                    // Textures
                    _bumpEffect.Parameters["BumpMap"].SetValue(_bumpTexture);
                    _bumpEffect.Parameters["WorldTexture"].SetValue(_renderTargetCube);
                        
                    // Fog
                    _bumpEffect.Parameters["FogStart"].SetValue(FogConstants.FogStart);
                    _bumpEffect.Parameters["FogEnd"].SetValue(FogConstants.FogEnd);
                    _bumpEffect.Parameters["FogColor"].SetValue(Color.White.ToVector3());
                        
                    // Light
                    _bumpEffect.Parameters["LightDirection"].SetValue(new Vector3(1, 0, 0));

                    part.Effect = _bumpEffect;
                    part.Effect.CurrentTechnique.Passes[0].Apply(); 
                }
                mesh.Draw();
            }
        }

        public override void Update(GameTime gt)
        {
            Rotation *= Matrix.CreateRotationY(0.01f);
            base.Update(gt);
        }
    }
}
